/*
 * ELRS2PWM - Arduino Mega2560连接ELRS 2.4G接收机，将CRSF协议转换为PWM信号输出
 * 
 * 本程序用于Arduino Mega2560开发板，连接ELRS 2.4G接收机，
 * 将接收机输出的CRSF协议数据解析后转换为标准PWM信号输出到指定引脚
 * 
 * 硬件连接：
 * ELRS接收机 -> Arduino Mega2560
 * 5V        -> 5V
 * GND       -> GND
 * TX        -> RX1 (Pin 19)
 * 
 * PWM输出引脚：
 * 通道1 -> Pin 2
 * 通道2 -> Pin 3
 * 通道3 -> Pin 4
 * 通道4 -> Pin 5
 * 通道5 -> Pin 6
 * 通道6 -> Pin 7
 * 通道7 -> Pin 8
 * 通道8 -> Pin 9
 */

#include <Servo.h>

// CRSF协议相关定义
#define CRSF_BAUDRATE           420000 // ELRS使用的CRSF波特率
#define CRSF_FRAME_SIZE_MAX     64
#define CRSF_HEADER_ORIGIN_MASK 0b11000000
#define CRSF_HEADER_ORIGIN_CRSF 0b00000000
#define CRSF_HEADER_TYPE_MASK   0b00111111
#define CRSF_FRAME_START_BYTE   0xC8
#define CRSF_TYPE_RC_CHANNELS   0x16

// CRSF帧结构
struct crsfFrameDef_t {
  uint8_t deviceAddress;
  uint8_t frameLength;
  uint8_t type;
  uint8_t payload[CRSF_FRAME_SIZE_MAX - 3 - 1];
  uint8_t crc; // 最后一个字节是CRC
};

// 通道数据结构
struct channelData_t {
  unsigned int ch0 : 11;
  unsigned int ch1 : 11;
  unsigned int ch2 : 11;
  unsigned int ch3 : 11;
  unsigned int ch4 : 11;
  unsigned int ch5 : 11;
  unsigned int ch6 : 11;
  unsigned int ch7 : 11;
  unsigned int ch8 : 11;
  unsigned int ch9 : 11;
  unsigned int ch10 : 11;
  unsigned int ch11 : 11;
  unsigned int ch12 : 11;
  unsigned int ch13 : 11;
  unsigned int ch14 : 11;
  unsigned int ch15 : 11;
} __attribute__((packed));

// 全局变量
Servo servos[8]; // 最多支持8个PWM输出通道
uint8_t crsfData[CRSF_FRAME_SIZE_MAX];
uint8_t crsfDataLength = 0;
uint32_t lastValidPacketTime = 0;
const uint32_t crsfTimeout = 500; // 500ms超时，认为信号丢失

// 通道值映射
int channelValues[16] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500};

// PWM输出引脚定义
const int pwmPins[8] = {2, 3, 4, 5, 6, 7, 8, 9};

// CRC8计算表
const uint8_t crc8_dvb_s2_table[256] = {
  0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54, 0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
  0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06, 0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
  0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0, 0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
  0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2, 0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
  0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9, 0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
  0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B, 0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
  0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D, 0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
  0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F, 0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
  0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB, 0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
  0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9, 0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
  0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F, 0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
  0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D, 0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
  0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26, 0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
  0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74, 0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
  0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82, 0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
  0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0, 0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
};

// 计算CRC8校验
uint8_t crc8_calc(uint8_t *data, uint8_t len) {
  uint8_t crc = 0;
  for (uint8_t i = 0; i < len; i++) {
    crc = crc8_dvb_s2_table[crc ^ data[i]];
  }
  return crc;
}

// 将CRSF的11位通道值(172-1811)映射到标准PWM值(1000-2000)
int mapChannelValue(int value) {
  // CRSF协议中，通道值范围是172-1811
  return map(value, 172, 1811, 1000, 2000);
}

// 解析CRSF数据帧
void parseCrsfPacket(uint8_t *data, uint8_t len) {
  // 检查帧长度是否合理
  if (len < 4) {
    return;
  }
  
  // 检查CRC
  uint8_t crc = crc8_calc(data, len - 1);
  if (crc != data[len - 1]) {
    return; // CRC错误
  }
  
  // 检查帧类型是否为RC通道数据
  if (data[2] != CRSF_TYPE_RC_CHANNELS) {
    return; // 不是通道数据
  }
  
  // 解析通道数据
  channelData_t *channelData = (channelData_t *)&data[3];
  
  // 更新通道值
  channelValues[0] = mapChannelValue(channelData->ch0);
  channelValues[1] = mapChannelValue(channelData->ch1);
  channelValues[2] = mapChannelValue(channelData->ch2);
  channelValues[3] = mapChannelValue(channelData->ch3);
  channelValues[4] = mapChannelValue(channelData->ch4);
  channelValues[5] = mapChannelValue(channelData->ch5);
  channelValues[6] = mapChannelValue(channelData->ch6);
  channelValues[7] = mapChannelValue(channelData->ch7);
  channelValues[8] = mapChannelValue(channelData->ch8);
  channelValues[9] = mapChannelValue(channelData->ch9);
  channelValues[10] = mapChannelValue(channelData->ch10);
  channelValues[11] = mapChannelValue(channelData->ch11);
  channelValues[12] = mapChannelValue(channelData->ch12);
  channelValues[13] = mapChannelValue(channelData->ch13);
  channelValues[14] = mapChannelValue(channelData->ch14);
  channelValues[15] = mapChannelValue(channelData->ch15);
  
  // 更新最后一次有效数据包时间
  lastValidPacketTime = millis();
}

void setup() {
  // 初始化串口1用于接收CRSF数据
  Serial1.begin(CRSF_BAUDRATE);
  
  // 初始化串口0用于调试输出
  Serial.begin(115200);
  Serial.println("ELRS2PWM - CRSF to PWM Converter");
  Serial.println("For Arduino Mega2560");
  
  // 初始化PWM输出通道
  for (int i = 0; i < 8; i++) {
    servos[i].attach(pwmPins[i]);
    servos[i].writeMicroseconds(1500); // 中间位置
  }
  
  Serial.println("Initialization complete. Waiting for CRSF data...");
}

void loop() {
  // 读取CRSF数据
  while (Serial1.available()) {
    uint8_t inChar = Serial1.read();
    
    // 检测帧起始字节
    if (crsfDataLength == 0 && inChar == CRSF_FRAME_START_BYTE) {
      crsfData[crsfDataLength++] = inChar;
    }
    // 读取帧长度
    else if (crsfDataLength == 1) {
      crsfData[crsfDataLength++] = inChar;
      // 帧长度字段包含了从Type字段到CRC字段的长度
      // 所以完整的帧长度是帧长度字段值+2(地址和长度字段)
    }
    // 继续读取剩余数据
    else if (crsfDataLength >= 2) {
      crsfData[crsfDataLength++] = inChar;
      
      // 检查是否已经读取完整个帧
      if (crsfDataLength >= crsfData[1] + 2) {
        // 解析数据帧
        parseCrsfPacket(crsfData, crsfDataLength);
        // 重置，准备读取下一帧
        crsfDataLength = 0;
      }
      
      // 防止缓冲区溢出
      if (crsfDataLength >= CRSF_FRAME_SIZE_MAX) {
        crsfDataLength = 0;
      }
    }
  }
  
  // 检查信号是否超时
  if (millis() - lastValidPacketTime > crsfTimeout) {
    // 信号丢失，将所有通道设置为中间值
    for (int i = 0; i < 16; i++) {
      channelValues[i] = 1500;
    }
  }
  
  // 更新PWM输出
  for (int i = 0; i < 8; i++) {
    servos[i].writeMicroseconds(channelValues[i]);
  }
  
  // 每秒打印一次通道值（用于调试）
  static uint32_t lastPrintTime = 0;
  if (millis() - lastPrintTime > 1000) {
    lastPrintTime = millis();
    
    Serial.print("CH Values: ");
    for (int i = 0; i < 8; i++) {
      Serial.print(channelValues[i]);
      Serial.print(" ");
    }
    Serial.println();
  }
}